package se.study.thread;

/**
 * @Author: tiger
 * @Date:2018/5/10
 * @Description:售票实例
 */
public class TicketDemo {
    public static void main(String[] args) {
        Runnable r = new TicketSell();

        Thread threadA = new Thread(r, "窗口A...");
        Thread threadB = new Thread(r, "窗口B...");
        Thread threadC = new Thread(r, "窗口C...");

        threadA.start();
        threadB.start();
        threadC.start();

    }

    /**
     * 同步锁：为了保证每个线程都能正常的执行原子操作，Java 线程引进了同步机制；同步锁也叫同步监听对象、同步监听器、互斥锁；
     * Java程序运行使用的任何对象都可以作为同步监听对象，但是一般我们把当前并发访问的共同资源作为同步监听对象
     * <p>
     * 注意：同步锁一定要保证是确定的，不能相对于线程是变化的对象；任何时候，最多允许一个线程拿到同步锁，谁拿到锁谁进入代码块，而其他的线程只能在外面等着
     */
    static class TicketSell implements Runnable {
        /**
         * 总共有25张
         */
        private static int num = 25;

        /**
         * 注意：不能直接用 synchronized 来修饰 run() 方法，因为如果这样做，那么就会总是第一个线程进入其中，而这个线程执行完所有操作，即卖完所有票了才会出来。
         */
        @Override
        public void run() {
            for (int i = 0; i < 25; i++) {
                // 买票25次
                synchronized (this.getClass()) {
                    // 需要同步操作的代码
                    if (num > 0) {
                        try {
                            // 休眠
                            Thread.sleep(10);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "卖出一张票，剩余" + (--num) + "张");
                    }
                }
            }
        }
    }
}
